﻿Imports System.Reflection
Imports System.Text.RegularExpressions
Imports System.Globalization

''' <summary>
''' 関連づけられたプロパティ
''' </summary>
''' <remarks></remarks>
Public Class RelatedProperty
    Inherits LiteralProperty

    Public Shared Shadows Function Create(current As PropertyInfo, upper As LiteralProperty) As RelatedProperty
        If current Is Nothing Then Throw New ArgumentNullException("current")
        If upper Is Nothing Then Throw New ArgumentNullException("upper")

        Dim c As New RelatedProperty
        c.PropertyInfo = current
        c.UpperProperty = upper

        'リテラル名キャッシュ
        Dim pname = current.Name
        Dim prefixPattern = String.Format("^(?<prefix>.*){0}$", current.PropertyType.Name)
        Dim m = Regex.Match(pname, prefixPattern, RegexOptions.IgnoreCase)
        If m.Success Then
            c.PrefixName = m.Groups("prefix").Value
        End If
        c.SystemName = c.PrefixName & c.UpperProperty.LiteralName

        Dim e As New LiteralNameBuildingEventArgs With {.PropertyInfo = upper, .Prefix = c.PrefixName, .LiteralName = c.SystemName}
        c.RaiseLiteralNameBuildingEvent(e)
        c.LiteralName = e.LiteralName

        'システム属性キャッシュ
        c.SystemValueAttribute = DirectCast(c.PropertyInfo.GetCustomAttributes(GetType(SpecialValueAttribute), False).FirstOrDefault, SpecialValueAttribute)

        'デリゲートコンパイル
        c.Getter = LiteralProperty.CreateGetDelegate(current.DeclaringType, current.Name)
        c.Setter = LiteralProperty.CreateSetDelegate(current.DeclaringType, current.Name)

        Return c
    End Function

    Private Sub New()
    End Sub

    Private _upperProperty As LiteralProperty
    ''' <summary>
    ''' 上層プロパティ
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property UpperProperty As LiteralProperty
        Get
            Return _upperProperty
        End Get
        Private Set(value As LiteralProperty)
            _upperProperty = value
        End Set
    End Property

    ''' <summary>
    ''' 接頭語
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Property PrefixName As String = String.Empty

    ''' <summary>
    ''' リテラルプロパティタイプを取得します
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides ReadOnly Property LiteralPropertyType As System.Type
        Get
            Return Me.UpperProperty.LiteralPropertyType
        End Get
    End Property

    ''' <summary>
    ''' リテラル値を取得します
    ''' </summary>
    ''' <param name="instance"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides Function GetLiteralValue(instance As Object) As Object
        Dim val = Me.GetValue(instance, Nothing)
        If val Is Nothing Then Return Nothing

        Return Me.UpperProperty.GetLiteralValue(val)
    End Function

    ''' <summary>
    ''' リテラル値を代入します
    ''' </summary>
    ''' <param name="instance"></param>
    ''' <param name="value"></param>
    ''' <remarks></remarks>
    Public Overrides Sub SetLiteralValue(instance As Object, value As Object)
        If value Is Nothing OrElse String.IsNullOrEmpty(value.ToString) Then Return

        Dim v = Me.GetValue(instance, Nothing)
        If v Is Nothing Then
            v = Activator.CreateInstance(Me.PropertyType)
            Me.SetValue(instance, v, Nothing)
        End If

        Me.UpperProperty.SetLiteralValue(v, value)
    End Sub
End Class